//: [Previous](@previous)
import Foundation
//: ## 继承 (inheritance)
/**
 1. 值类型(枚举, 结构体)不支持继承, 只有类支持继承, 也就是说只有引用类型才支持继承
 2. 没有父类的类, 成为: 基类. (Swift并没有像OC, Java那样的规定:任何类最终都要继承自某个基类)
 3. 子类可以重写父类的下标, 方法, 属性, 重写必须加上override关键字(重写的本质是父类本来有的方法,子类需要用到这个方法但是想要有别的实现,所以重写覆盖掉父类的实现.  下标的本质也是方法, 属性里面有计算属性,计算属性本质也是方法, 所以下标,方法,属性的重写其实都是对方法的重写)
 */

//: ## 内存结构
//创建类:动物, 创建类:狗, 狗继承自动物. 创建类:二哈, 二哈继承自狗. 然后观察这3个类的内存结构
class Animal {
    var age = 0
}
class Dog : Animal {
    var weight = 0
}
class ErHa : Dog {
    var IQ = 0
}

let a = Animal()
a.age = 10
/**
 1.因为类是存放在堆空间, 堆空间的内存必须是16的倍数
 2.堆空间的存储前8个字节固定是存放类型信息, 第二个8个字节(9~18)是存放引用计数相关的东西
 从第三个8个字节才开始放真正的存储内容,就是Animal的age, age是8个字节, 所以一个animal对象是8+8+8 = 24个字节,但是因为类在堆空间中,堆空间是16的倍数,所以Animal类真正的内存是占用了32个字节
 
 32个字节具体展示: 每一行是8个字节
 0x00000001000073e0 (类型信息)
 0x0000000000000002 (引用计数)
 0x000000000000000a (age = 10)
 0x0000000000000000 (nil)
*/

let b = Dog()
b.age = 10
b.weight = 20
/*
 继承其实就是把父类的属性和方法都拿过来
 class Dog : Animal {
     var weight = 0
 }
 
 class Dog {
     var age = 0
     var weight = 0
 }
 2种写法其实是一样的,其实就是把父类的age拿到自己的内存而已
 
 
 1.类的前16个字节固定
 2.Dog继承自Animal, 所以内部还需要存放Animal的age, 所以占用了8个字节
 3.Dog自己的weight占用8个字节
 总内存 16+8+8 = 32
 32个字节具体展示:
 0x0000000100007490 (类型信息)
 0x0000000000000002 (引用计数)
 0x000000000000000a (age = 10)
 0x0000000000000014 (weight = 20)
 */

let c = ErHa()
c.age = 10
c.weight = 20
c.IQ = 30
/*
 1.类的前16个字节固定
 2.ErHa继承自Dog, 所以内部还需要存放Dog的weight, 所以占用了8个字节
 3.Dog继承自Animal, 所以内部还需要存放Animal的age, 所以占用了8个字节
 4.ErHa自己的IQ占用8个字节
 5.内存对齐,16倍数
 总内存 16+8+8+8 = 40 -> 内存补齐 -> 48
 48个字节具体展示:
 0x0000000100007490 (类型信息)
 0x0000000000000002 (引用计数)
 0x000000000000000a (age = 10)
 0x0000000000000014 (weight = 20)
 0x000000000000001e (IQ = 30)
 0x0000000000000000 (nil)
 */
//: ## 重写示例方法 / 下标
// 父类
class Car {
    func logo() {
        print("a car")
    }
    
    subscript(index: Int) -> Int {
        return index
    }
}

var car: Car
car = Car()
car.logo()
//a car
//print(car[2])
//2

// 重写, audi继承自Car
class Audi: Car {
    //重写父类的方法,必须加override
    override func logo() {
        // 假如需要在重写的方法里面调用父类的原来的方法, 用super.+方法名
        super.logo()
        print("My Audi")
    }
    
    //重写下标, 也是要加override, 反正只要看到override,就是重写, 因为不加的话重写会报错
    override subscript(index: Int) -> Int {
        // 这里是调用了父类的下标内容(输入什么int,就返回什么int) 再+1
        return super[index] + 1
    }
    
}

//把原本的父类指针car, 指向子类audi, 这个也叫做多态
car = Audi()
car.logo()
// a car
//My Audi
//print(car[2])
// 3
//: ## 重写类型的 方法 / 下标
//类型方法和属性 前面可以用class 或者 static 修饰, 这个是之前的内容
// 被 class 修饰的类型方法/下标, 允许 被子类重写
// 被 static 修饰的类型方法/下标, 不允许 被子类重写
class Ball {
    class func play() {
        print("play")
    }
    class subscript(index: Int) -> Int {
        return index
    }
}

Ball.play()
//play
print(Ball[10])
//10

//重写
class PpBall: Ball {
    override class func play() {
        super.play()
        print("+ PpBall")
    }
    override class subscript(index: Int) -> Int {
        return super[index] + 1
    }
}
PpBall.play()
//play
//+ PpBall
//print(PpBall[20])
//21
//*小提示: 父类A,子类B,B的子类C, 现在有3个类. 父类A的方法或者下标永远class修饰, 子类B可以重写, 子类B的用static修饰了的话, 子类C就不可以重写了, 也就是说当一个类的方法或者下标, 用static修饰后, 他的子类就不可以重写, 因为重写父类方法的时候相当于要去重写static. 但是class修饰的, 子类可以重写, 相当于重写父类的class的方法, 所以可以一直重写
//: ## 重写属性
/*
 1. 子类可以将父类的属性(存储 / 计算)重写为 计算属性[是一定只能是重写为计算属性,不能重写成存储属性]
 2. 只能重写 var 属性, 不能重写 let 属性, 因为假如重写了父类的let属性, 子类里面的set和get方法可以随便赋值,就会修改到let的父类属性
 3. 重写时, 属性名称 / 类型 要一致
 4. 子类重写后的属性权限, 不能小于 父类的属性权限(要是儿子不比父亲强,何必重写,要一代比一代强嘛)
   4.1 如果父类属性是只读(只有get没有set), 那么子类重写后的属性可以是只读, 也可以是可读可写(get set)
   4.2 如果父类属性是可读写(有get有set), 那么子类重写后的属性就必须也是可读可写
 */

/*
class A {
    var age = 0 // 存储属性
}
class B: A {
    //假如想重写父类的存储属性,后续对象使用的时候,和这个属性直接在父类的时候是一样的,没有意义
    override var age = 0
    var weight = 0
}
 var c = B()
 c.age = 10
 //这个时候这个age,明明是父类的存储属性,但是假如要被子类重写,此时这个内存应该是父类还是子类呢?明明在父类的时候就和在子类的时候一样的意义,为什么还要重写.所以子类不可以重写父类的存储属性
*/
//: ## 重写实例属性
// 从父类继承到子类的存储属性,在子类的对象中还是要分配子类的自己存储空间去存储的
class D {
    var age: Int = 0
    var ageX2: Int {
        set {
            print("父类C ageX2 setter方法")
            age = newValue / 2
        }
        get {
            print("父类C ageX2 getter方法")
            return age * 2
        }
    }
}

var dd: D
dd = D()
dd.age = 6
print(dd.ageX2)
//1.父类C ageX2 getter方法
//2.12
dd.ageX2 = 10
//1.父类C ageX2 setter方法

//E继承自D, 重写父类的存储属性和计算属性 变为都是计算属性
class E: D {
    override var age: Int {
        set {
            print("子类E age setter方法")
            super.age = newValue > 0 ? newValue : 0
        }
        get {
            print("子类E age getter方法")
            return super.age
        }
    }
    override var ageX2: Int {
        set {
            print("子类E ageX2 setter方法")
            super.ageX2 = newValue > 0 ? newValue : 0
        }
        get {
            print("子类E ageX2 getter方法")
            return super.ageX2
        }
    }
}

print("-------")
dd = E()
dd.age = 20
//子类E age setter方法
print(dd.ageX2)
//子类E ageX2 getter方法
//父类C ageX2 getter方法
//子类E age getter方法
//40
dd.ageX2 = 30
//子类E ageX2 setter方法
//父类C ageX2 setter方法
//子类E age setter方法

//: ## 重写类型属性
/*
 1. 被 class 修饰的 计算类型属性, 可以被子类重写(计算属性不可以被class修饰)
 2. 被 static 修饰的 类型属性(存储/计算), 不可以被子类重写
 */
//: ## 属性观察器
// 可以在子类中为父类属性(除了只读计算属性 / let属性) 添加属性观察器
// 例子1
class F {
    var age = 10
}
class ff: F {
    override var age: Int {
        willSet {
            print("sub ff willSet", newValue)
        }
        didSet {
            print("sub ff didSet", oldValue, age)
        }
    }
}
print("------")
var fff = ff()
fff.age = 20
//sub ff willSet 20
//sub ff didSet 10 20
//例子2
class G {
    //父类的存储属性, 已经有属性观察器
    var age: Int = 1 {
        willSet {
            print("fu G willSet", newValue)
        }
        didSet {
            print("fu G didSet", oldValue, age)
        }
    }
}
class gg: G {
    //子类对父类的存储属性添加属性观察器, 只是添加观察器不是改成计算属性哦, 因为没有set和get
    override var age: Int {
        willSet {
            print("sub gg willSet", newValue)
        }
        didSet {
            print("sub gg didSet", oldValue, age)
        }
    }
}
print("------")
var ggg = gg()
ggg.age = 20
//sub gg willSet 20 因为ggg是子类对象,所以赋值先调用子类的will
//fu G willSet 20  子类中的age其实是父类的存储属性,所以内存还是在父类中存储,所以修改的是父类内存中的值,所以就触发了父类的will
//fu G didSet 1 20 父类的did也改完
//sub gg didSet 1 20 这个时候才到子类的did
//例子3
class H {// 父类的计算类型属性
    class var age: Int {
        set{
            print("fu H set", newValue)
        }
        get {
            print("fu H get")
            return 20//这里要注意,是写死了一定返回20,就是不管怎么改,都是20
        }
    }
}
class hh: H {
    override static var age: Int{
        willSet {
            print("sub hh willSet", newValue)
        }
        didSet {
            print("sub hh didSet", oldValue, age)
        }
    }
}
print("-----")
hh.age = 10
//fu H get 因为要除非修改值了,所以肯定要先获取到旧的值,所以will之前一定会先执行获取旧值
//sub hh willSet 10
//fu H set 10 子类开始执行set,其实就是调用父类的set
//fu H get
//sub hh didSet 20 20
//: ## final
/*
 1. 被final修饰的 方法/ 下标/ 属性, 禁止被重写
 1. 被final修饰的 类, 禁止被继承
 */
final class I {//final 表示这个类不能被继承
    final var age = 10 //final 表示这个属性不能被重写
}

































